package www.sofn.com.accounts;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import www.sofn.com.accounts.domain.LoginInfoVO;
import www.sofn.com.constant.Constants;
import www.sofn.com.domain.vo.PersonalInfoVo;
import www.sofn.com.exception.ValidateException;
import www.sofn.com.security.domain.vo.TokenInfoVO;
import www.sofn.com.security.service.TokenService;
import www.sofn.com.sys.user.SysUserService;
import www.sofn.com.sys.user.domain.pojo.SysUserPO;
import www.sofn.com.utils.ServletUtils;

import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AccountsService  {

    @Resource
    private TokenService tokenService;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    public String doLogin(LoginInfoVO loginInfoVO) {
        String captcha = redisTemplate.opsForValue().get(Constants.CAPTCHA_PREFIX + loginInfoVO.getCaptchaId());
        redisTemplate.delete(Constants.CAPTCHA_PREFIX + loginInfoVO.getCaptchaId());
        if (!StrUtil.equalsIgnoreCase(captcha, loginInfoVO.getCaptcha())) {
            throw new ValidateException("登录失败！验证码错误");
        }
        Authentication authentication = null;
        try {
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginInfoVO.getUsername(), loginInfoVO.getPassword()));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new ValidateException("登录失败:用户名或密码不正确！");
            }
            if (e instanceof InternalAuthenticationServiceException) {
                throw new ValidateException("登录失败:用户名不存在！");
            } else {
                throw new ValidateException(e.getMessage());
            }
        }
        final User user = (User) authentication.getPrincipal();
        final String token = tokenService.createToken(new TokenInfoVO(user.getUsername(),
                user.getAuthorities().stream().map(
                        (GrantedAuthority t) -> t.getAuthority()
                ).collect(Collectors.toSet())));
        return token;
    }

    public PersonalInfoVo getPersonal() {
        final TokenInfoVO tokenInfo = tokenService.getTokenInfo(ServletUtils.getRequest());
        if (ObjectUtil.isNull(tokenInfo)) return null;
        String username = tokenInfo.getUsername();
        final String jsonPersonalInfo = redisTemplate.opsForValue().get(Constants.PERSONAL_CACHE_PREFIX + username);
        PersonalInfoVo personalInfoVo = null;
        if (StrUtil.isNotBlank(jsonPersonalInfo)) {
            personalInfoVo = JSONUtil.toBean(jsonPersonalInfo, PersonalInfoVo.class);
        } else {
            final SysUserPO userPO = sysUserService.selectUserByUsername(username);
            personalInfoVo = BeanUtil.toBean(userPO, PersonalInfoVo.class);
            personalInfoVo.setAuthorities(sysUserService.findResourceCodeByUserId(userPO.getId()));
            personalInfoVo.setRoles(sysUserService.findRolesByUserId(userPO.getId()));
            redisTemplate.opsForValue().set(Constants.PERSONAL_CACHE_PREFIX + userPO.getUsername(), JSONUtil.toJsonStr(personalInfoVo), 5, TimeUnit.MINUTES);
        }
        return personalInfoVo;

    }

}



